package com.nervenets.general.aspect;

import com.alibaba.fastjson.JSON;
import com.nervenets.general.Global;
import com.nervenets.general.enumeration.Platform;
import com.nervenets.general.event.SysLogEvent;
import com.nervenets.general.jwt.util.JwtUtils;
import com.nervenets.general.model.SysLogInfo;
import com.nervenets.general.utils.HttpTools;
import com.nervenets.general.utils.JodaUtils;
import com.nervenets.general.utils.SpringContextHolder;
import com.nervenets.general.wapper.NerveNetsHttpServletRequestWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

@Aspect
@Slf4j
@Component
public class SysLogAspect {
    @Around("@annotation(sysLog)")
    public Object around(ProceedingJoinPoint point, SysLog sysLog) throws Throwable {
        Class<?> clazz = point.getTarget().getClass();
        String className = clazz.getName();
        Signature signature = point.getSignature();
        String classMethodName = signature.getName();

        HttpServletRequest request = Objects.requireNonNull(HttpTools.getHttpRequest());

        SysLogInfo logInfo = SysLogInfo.builder()
                .className(className)
                .classMethod(classMethodName)
                .createTime(JodaUtils.getTimestamp())
                .ip(HttpTools.getIp(request))
                .userAgent(request.getHeader("User-Agent"))
                .userPlatform(Platform.customValueOf(request.getHeader(Global.Constants.PLATFORM_KEY)))
                .user(JwtUtils.getUser())
                .logKey(sysLog.key())
                .logValue(sysLog.value())
                .logTags(Arrays.asList(sysLog.tags()))
                .build();

        if (request instanceof NerveNetsHttpServletRequestWrapper) {
            String body = ((NerveNetsHttpServletRequestWrapper) request).getBody();
            logInfo.setParams(body);
        } else {
            logInfo.setParams(JSON.toJSONString(request.getParameterMap()));
        }

        Api api = clazz.getAnnotation(Api.class);
        if (null != api) {
            logInfo.setApiName(api.value());
            logInfo.setApiTags(Arrays.asList(api.tags()));
        }

        if (signature instanceof MethodSignature) {
            Object target = point.getTarget();
            Method method = target.getClass().getMethod(signature.getName(), ((MethodSignature) signature).getParameterTypes());
            ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
            if (null != apiOperation) {
                logInfo.setClassMethodFunc(apiOperation.value());
            }
        }

        logInfo.setStartTime(System.currentTimeMillis());
        Object obj = point.proceed();
        logInfo.setEndTime(System.currentTimeMillis());
        logInfo.setResult(JSON.toJSONString(obj));

        SpringContextHolder.publishEvent(new SysLogEvent(logInfo));

        return obj;
    }
}
